import fs from "fs";
import path from "path";

export class Addon {
  #position = {};
  #loaderType = "";
  setPosition = (position) => {
    this.#position = position;
  };
  setLoaderType = (loaderType) => {
    this.#loaderType = loaderType;
  };
  create = (info) => {
    this.createAddon(info);
    this.createLoader(info);
  };
  createLoader = ({
    entityName,
    contributes,
    cpName,
    cp,
    implClassName,
    publisher,
  }) => {
    Object.keys(this.template.loader).forEach((key) => {
      const path = this.template.loader[key].path(entityName);
      const file = this.template.loader[key].content({
        entityName,
        contributes,
        cpName,
        cp,
        implClassName,
        publisher,
      });
      this.#createFile(path, file);
    });
  };

  createAddon = ({
    entityName,
    contributes,
    cpName,
    cp,
    implClassName,
    publisher,
  }) => {
    Object.keys(this.template.addon).forEach((key) => {
      const path = this.template.addon[key].path(entityName);
      const file = this.template.addon[key].content({
        entityName,
        contributes,
        cpName,
        cp,
        implClassName,
        publisher,
      });
      this.#createFile(path, file);
    });
  };

  #createFile(filePath, fileContent) {
    try {
      let absPath = this.#position.AbsPath;
      let cwd = findRushJSON(); // cli的工作目录，一定是在front-theory目录内
      cwd = cwd.replace(/front-theory.*/, "front-theory"); // 在front-theory的下级目录的话，将下级干掉
      absPath = absPath.replace(/.*front-theory/, cwd); // 设置为工作目录下的目录
      absPath = path.dirname(absPath);
      const realPath = path.join(absPath, filePath);
      // 确保路径存在，如果不存在则创建
      const directory = path.dirname(realPath);
      if (!fs.existsSync(directory)) {
        fs.mkdirSync(directory, { recursive: true });
        console.log("创建目录：" + directory);
      }

      // 创建文件
      fs.writeFileSync(realPath, fileContent, "utf-8");
      console.log("创建文件：" + realPath);
    } catch (err) {
      console.error(err);
    }
  }

  #loaderName = (entityName) => {
    return `${this.#position.Name}.${this.#loaderType}.${entityName}`;
  };

  template = {
    loader: {
      index_ts: {
        path: (entityName) => {
          return `${this.#position.Application}/loader/${entityName}/index.ts`;
        },
        content: ({
          entityName,
          contributes,
          cpName,
          cp,
          implClassName,
          publisher,
        }) => `
import { IExpansionImplement } from '@q7/expansions';
import { IApplicationActiveContext } from '@q7/micro-core-base-app/application';

export default class ${formatString(
          this.#position.Name,
        )}Loader${entityName}Impl implements IExpansionImplement {
  activate(ctx: IApplicationActiveContext): void {
    ctx.loaders.register('${this.#loaderName(entityName)}', async () => {
      const { manifest } = await import('${this.template.addon.manifest_ts
        .path(entityName)
        .replace(/^\.\//, "")}');
      return manifest;
    });
  }
}
`,
      },
      manifest_json: {
        path: (entityName) => {
          return `${this.#position.Application}/loader/${entityName}/manifest.json`;
        },
        content: ({
          entityName,
          contributes,
          cpName,
          cp,
          implClassName,
          publisher,
        }) => `{
  "$schema": "http://front.q7link.com:3000/json-schema/manifest/application.json",
  "name": "${this.#position.Name}.loader.${entityName}",
  "publisher": "${publisher}",
  "version": "1.0.0",
  "activationEvents": [
    "Construct"
  ],
  "dependencies": {
    "loaders": "*",
    "form.loader": "*"
  },
  "description": "",
  "contributes": {
    "loaders": [
      {
        "cp": "${this.#loaderType}",
        "name": "${this.#loaderName(entityName)}",
        "match": "${entityName}"
      }
    ]
  }
}`,
      },
    },
    addon: {
      index_tsx: {
        path: (entityName) => {
          return `${this.#position.Extension}/biz-form/${entityName}/index.tsx`;
        },
        content: ({
          entityName,
          contributes,
          cpName,
          cp,
          implClassName,
          publisher,
        }) => `import { IActivateContext, IExpansionImplement } from '@q7/expansions';

export class ${implClassName} implements IExpansionImplement {
  activate(ctx: IActivateContext) {
    ctx.${contributes}.register('${cpName}', () => {
      return 1=2;
    });
  }

  deactivate(): void {}
}

export default new ${implClassName}();`,
      },
      manifest_json: {
        path: (entityName) => {
          return `${this.#position.Extension}/biz-form/${entityName}/manifest.json`;
        },
        content: ({
          entityName,
          contributes,
          cpName,
          cp,
          implClassName,
          publisher,
        }) => `{
  "name": "${entityName}@${contributes}@${cp}",
  "publisher": "${publisher}",
  "version": "1.0.0",
  "activationEvents": ["Construct"],
  "contributes": {
    "${contributes}": [
      {
        "name": "${cpName}",
        "cp": "${cp}"
      }
    ]
  }
}`,
      },
      manifest_ts: {
        path: (entityName) => {
          return `${this.#position.Extension}/biz-form/${entityName}/manifest.ts`;
        },
        content: ({
          entityName,
          contributes,
          cpName,
          cp,
          implClassName,
          publisher,
        }) => `import manifestJSON from './manifest.json';

export const manifest = {
  ...manifestJSON,
  async localImpl() {
    const { ${implClassName} } = await import('./index');
    return new ${implClassName}();
  }
};`,
      },
    },
  };
}

export function findRushJSON() {
  const cwd = process.cwd();
  const rushJsonPath = path.join(cwd, "rush.json");
  if (fs.existsSync(rushJsonPath)) {
    return cwd;
  }
  const pathArr = cwd.split(path.sep);
  for (let i = 0; i < pathArr.length; i++) {
    const pathStr = pathArr.slice(0, i).join(path.sep);
    const rushJsonPath = path.join(pathStr, "rush.json");
    if (fs.existsSync(rushJsonPath)) {
      return pathStr;
    }
  }
}

function formatString(inputString) {
  // 将字符串按照 "-" 分割成数组
  let parts = inputString.replace("@q7/", "").split("-");

  // 遍历数组，将每个单词的首字母转为大写
  for (let i = 1; i < parts.length; i++) {
    parts[i] = parts[i].charAt(0).toUpperCase() + parts[i].slice(1);
  }

  // 将数组中的单词连接起来，并返回结果
  return parts.join("");
}
